﻿using System;
using System.Linq;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
using TestHarnessWebRole.Data;
using AntsCode.StorageClientExtensions;

namespace TestHarnessWebRole
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            // Create tables            
            CloudStorageAccount account = CloudStorageAccount.FromConfigurationSetting("StorageConnectionString");
            CloudTableClient.CreateTablesFromModel(typeof(TestTableServiceContext), account.TableEndpoint.ToString(), account.Credentials);

            // Populate test data
            TestData.AddTestDataIfNotExists();

            // Create instance of XTableServiceContext
            TestTableServiceContext context = new TestTableServiceContext(account.TableEndpoint.ToString(), account.Credentials);

            // Raw Customers
            RawCustomerTest.RunQuery(context, from c in context.Customer
                                              select c);

            // Raw Orders
            RawOrderTest.RunQuery(context, from c in context.Order
                                           select c);

            // Test 1: Select
            Test1.RunQuery(context, from c in context.Customer
                                    select new
                                    {
                                        c.FirstName,
                                        c.LastName
                                    });

            // Test 2: Join
            Test2.RunQuery(context, from o in context.Order
                                    join c in context.Customer on o.CustomerId equals c.RowKey
                                    select new
                                    {
                                        o.OrderNo,
                                        c.FirstName,
                                        c.LastName,
                                        o.Total
                                    });

            // Test 3: Join (asynchronous)
            Test3.RunQuery(context, from o in context.Order
                                    join c in context.Customer on new { RowKey = o.CustomerId, PartitionKey = "Customers", Async = true } equals new { c.RowKey, c.PartitionKey, Async = true }
                                    select new
                                    {
                                        o.OrderNo,
                                        c.FirstName,
                                        c.LastName,
                                        o.Total
                                    });

            // Test 4: Join and Where
            Test4.RunQuery(context, from o in context.Order
                                    join c in context.Customer on o.CustomerId equals c.RowKey
                                    where o.OrderNo == "20020"
                                    select new
                                    {
                                        o.OrderNo,
                                        c.FirstName,
                                        c.LastName,
                                        o.Total
                                    });

            // Test 5: Join on multiple properties
            Test5.RunQuery(context, from o in context.Order
                                    join c in context.Customer on new { RowKey = o.CustomerId, PartitionKey = "Customers" } equals new { c.RowKey, c.PartitionKey }
                                    select new
                                    {
                                        o.OrderNo,
                                        c.FirstName,
                                        c.LastName,
                                        o.Total
                                    });

            // Test 6: Join on multiple properties (asynchronous)
            Test6.RunQuery(context, from o in context.Order
                                    join c in context.Customer on new { RowKey = o.CustomerId, PartitionKey = "Customers", Async = true } equals new { c.RowKey, c.PartitionKey, Async = true }
                                    where o.OrderNo == "20020"
                                    select new
                                    {
                                        o.OrderNo,
                                        c.FirstName,
                                        c.LastName,
                                        o.Total
                                    });

            // Test 7: Multiple Joins (companies are dependent on customers)
            Test7.RunQuery(context, from o in context.Order
                                    join c in context.Customer on new { RowKey = o.CustomerId, PartitionKey = "Customers" } equals new { c.RowKey, c.PartitionKey }
                                    join co in context.Company on new { RowKey = c.CompanyId, PartitionKey = "Companies" } equals new { co.RowKey, co.PartitionKey }
                                    join l in context.Location on new { RowKey = co.LocationId, PartitionKey = "Locations" } equals new { l.RowKey, l.PartitionKey }
                                    select new
                                    {
                                        o.OrderNo,
                                        co.Name,
                                        c.FirstName,
                                        c.LastName,
                                        o.Total,
                                        Location = l.Name
                                    });

            // Test 8: Multiple Joins (companies are dependent on orders)
            Test8.RunQuery(context, from o in context.Order
                                    join c in context.Customer on new { RowKey = o.CustomerId, PartitionKey = "Customers" } equals new { c.RowKey, c.PartitionKey }
                                    join co in context.Company on new { RowKey = o.CompanyId, PartitionKey = "Companies" } equals new { co.RowKey, co.PartitionKey }
                                    join l in context.Location on new { RowKey = co.LocationId, PartitionKey = "Locations" } equals new { l.RowKey, l.PartitionKey }
                                    select new
                                    {
                                        o.OrderNo,
                                        co.Name,
                                        c.FirstName,
                                        c.LastName,
                                        o.Total,
                                        Location = l.Name
                                    });

            // Test 9: Multiple Joins (companies & locations are dependent on orders)
            Test9.RunQuery(context, from o in context.Order
                                    join c in context.Customer on new { RowKey = o.CustomerId, PartitionKey = "Customers" } equals new { c.RowKey, c.PartitionKey }
                                    join co in context.Company on new { RowKey = o.CompanyId, PartitionKey = "Companies" } equals new { co.RowKey, co.PartitionKey }
                                    join l in context.Location on new { RowKey = o.LocationId, PartitionKey = "Locations" } equals new { l.RowKey, l.PartitionKey }
                                    select new
                                    {
                                        o.OrderNo,
                                        co.Name,
                                        c.FirstName,
                                        c.LastName,
                                        o.Total,
                                        Location = l.Name
                                    });

            // Test 10: Multiple Joins (asynchronous)
            Test10.RunQuery(context, from o in context.Order
                                     join c in context.Customer on new { RowKey = o.CustomerId, PartitionKey = "Customers", Async = true } equals new { c.RowKey, c.PartitionKey, Async = true }
                                     join co in context.Company on new { RowKey = o.CompanyId, PartitionKey = "Companies", Async = true } equals new { co.RowKey, co.PartitionKey, Async = true }
                                     join l in context.Location on new { RowKey = o.LocationId, PartitionKey = "Locations", Async = true } equals new { l.RowKey, l.PartitionKey, Async = true }
                                     select new
                                     {
                                         o.OrderNo,
                                         co.Name,
                                         c.FirstName,
                                         c.LastName,
                                         o.Total,
                                         Location = l.Name
                                     });

            // Test 11: First
            Test11.InitSingle(context);
            Test11.RunSingle(context, (from c in context.Customer
                                       where c.FirstName == "Peter"
                                       select new
                                       {
                                           c.FirstName,
                                           c.LastName
                                       }).First());

            // Test 12: FirstOrDefault
            Test12.InitSingle(context);
            Test12.RunSingle(context, (from c in context.Customer
                                       where c.FirstName == "DoesNotExist"
                                       select new
                                       {
                                           c.FirstName,
                                           c.LastName
                                       }).FirstOrDefault());

            // Test 13: Take
            Test13.RunQuery(context, (from c in context.Customer
                                      select new
                                      {
                                          c.FirstName,
                                          c.LastName
                                      }).Take(3));

            // Test 14: Join & FirstOrDefault
            Test14.InitSingle(context);
            Test14.RunSingle(context, (from o in context.Order
                                       join c in context.Customer on o.CustomerId equals c.RowKey
                                       select new
                                       {
                                           o.OrderNo,
                                           c.FirstName,
                                           c.LastName,
                                           o.Total
                                       }).FirstOrDefault());

            // Test 15: Get Continuation Token
            Test15.ShowContinuationToken = true;
            Test15.RunQuery(context, (from c in context.Customer
                                      select new
                                      {
                                          c.FirstName,
                                          c.LastName
                                      }).Take(3));

            Test16.ContinuationToken = Test15.ContinuationToken;

            // Test 16: Use Continuation Token
            Test16.RunQuery(context, (from c in context.Customer
                                      select new
                                      {
                                          c.FirstName,
                                          c.LastName
                                      }).Take(3));

            // Test 17: Get Continuation Token with Join
            Test17.ShowContinuationToken = true;
            Test17.RunQuery(context, (from o in context.Order
                                      join c in context.Customer on new { RowKey = o.CustomerId, PartitionKey = "Customers" } equals new { c.RowKey, c.PartitionKey }
                                      join co in context.Company on new { RowKey = o.CompanyId, PartitionKey = "Companies" } equals new { co.RowKey, co.PartitionKey }
                                      join l in context.Location on new { RowKey = co.LocationId, PartitionKey = "Locations" } equals new { l.RowKey, l.PartitionKey }
                                      select new
                                      {
                                          o.OrderNo,
                                          co.Name,
                                          c.FirstName,
                                          c.LastName,
                                          o.Total,
                                          Location = l.Name
                                      }).Take(3));

            Test18.ContinuationToken = Test17.ContinuationToken;

            // Test 18: Use Continuation Token with Join
            Test18.RunQuery(context, (from o in context.Order
                                      join c in context.Customer on new { RowKey = o.CustomerId, PartitionKey = "Customers" } equals new { c.RowKey, c.PartitionKey }
                                      join co in context.Company on new { RowKey = o.CompanyId, PartitionKey = "Companies" } equals new { co.RowKey, co.PartitionKey }
                                      join l in context.Location on new { RowKey = co.LocationId, PartitionKey = "Locations" } equals new { l.RowKey, l.PartitionKey }
                                      select new
                                      {
                                          o.OrderNo,
                                          co.Name,
                                          c.FirstName,
                                          c.LastName,
                                          o.Total,
                                          Location = l.Name
                                      }).Take(3));

            // Test 19: Outer Join
            Test19.RunQuery(context, from o in context.Order
                                     join c in context.Customer on o.CustomerId equals c.RowKey into g
                                     from c in g.DefaultIfEmpty()
                                     select new
                                     {
                                         o.OrderNo,
                                         c.FirstName,
                                         c.LastName,
                                         o.Total
                                     });


            // Test 20: Multiple Outer Joins
            Test20.RunQuery(context, from o in context.Order
                                     join c in context.Customer on new { RowKey = o.CustomerId, PartitionKey = "Customers" } equals new { c.RowKey, c.PartitionKey }
                                     join co in context.Company on new { RowKey = c.CompanyId, PartitionKey = "Companies" } equals new { co.RowKey, co.PartitionKey } into oco
                                     from co in oco.DefaultIfEmpty()
                                     join l in context.Location on new { RowKey = co == null ? null : co.LocationId, PartitionKey = "Locations" } equals new { l.RowKey, l.PartitionKey } into col
                                     from l in col.DefaultIfEmpty()
                                     select new
                                     {
                                         o.OrderNo,
                                         Name = co == null ? null : co.Name,
                                         Location = l == null ? null : l.Name,
                                         c.FirstName,
                                         c.LastName,
                                         o.Total,
                                     });

            // Test 21: OrderBy
            Test21.RunQuery(context, from x in context.Customer
                                     orderby x.FirstName
                                     select new
                                     {
                                         x.FirstName,
                                         x.LastName
                                     });

            // Test 22: OrderBy Descending
            Test22.RunQuery(context, from x in context.Customer
                                     orderby x.FirstName descending
                                     select new
                                     {
                                         x.FirstName,
                                         x.LastName
                                     });

            // Test 23: ThenBy
            Test23.RunQuery(context, from x in context.Customer
                                     orderby x.FirstName, x.LastName
                                     select new
                                     {
                                         x.FirstName,
                                         x.LastName
                                     });

            // Test 24: ThenBy Descending
            Test24.RunQuery(context, from x in context.Customer
                                     orderby x.FirstName descending, x.LastName descending
                                     select new
                                     {
                                         x.FirstName,
                                         x.LastName
                                     });

            // Test 25: Query parameter escaping (member, constant, method call, CompareTo, CompareTo with member)
            string searchValue = "Widget & Co.";

            Test25.RunQuery(context, from x in context.Company
                                     where x.Name == searchValue && x.Name == "Widget & Co." && x.Name == GetFilterCriteria() && x.Name.CompareTo("Widget & Co.") >= 0 && x.Name.CompareTo(searchValue) >= 0
                                     select new
                                     {
                                         x.Name
                                     });

            // Test 26: Single resource
            Test26.InitSingle(context);
            Test26.RunSingle(context, (from x in context.Company
                                       where x.PartitionKey == "Companies" && x.RowKey == "xxx"
                                       select new
                                       {
                                           x.Name
                                       }).FirstOrDefault());
        }

        public string GetFilterCriteria()
        {
            return "Widget & Co.";
        }
    }
}